home *** CD-ROM | disk | FTP | other *** search
/ Aminet 45 / Aminet 45 (2001)(GTI - Schatztruhe)[!][Oct 2001].iso / Aminet / gfx / x11 / x3270_3_2_16.lha / amiga_src / save.c < prev    next >
C/C++ Source or Header  |  2001-06-23  |  16KB  |  740 lines

  1. /*
  2.  * Copyright 1994, 1995, 1999, 2000 by Paul Mattes.
  3.  *  Permission to use, copy, modify, and distribute this software and its
  4.  *  documentation for any purpose and without fee is hereby granted,
  5.  *  provided that the above copyright notice appear in all copies and that
  6.  *  both that copyright notice and this permission notice appear in
  7.  *  supporting documentation.
  8.  */
  9.  
  10. /*
  11.  *    save.c
  12.  *        Implements the response to the WM_SAVE_YOURSELF message and
  13.  *        x3270 profiles.
  14.  */
  15.  
  16. #include "globals.h"
  17. #include <X11/StringDefs.h>
  18. #include <X11/Xatom.h>
  19. #include <pwd.h>
  20. #include <errno.h>
  21. #include <time.h>
  22. #include "appres.h"
  23. #include "resources.h"
  24.  
  25. #include "savec.h"
  26. #include "popupsc.h"
  27. #include "utilc.h"
  28.  
  29.  
  30. /* Support for WM_SAVE_YOURSELF. */
  31.  
  32. extern Boolean    keypad_changed;
  33. extern Boolean  keypad_popped;
  34. extern Boolean    model_changed;
  35. extern Boolean    scrollbar_changed;
  36. extern Boolean    efont_changed;
  37. extern Boolean    oversize_changed;
  38. extern Boolean    scheme_changed;
  39. extern Boolean    keymap_changed;
  40. extern Boolean    charset_changed;
  41.  
  42. char           *command_string = CN;
  43.  
  44. static char    *cmd;
  45. static int      cmd_len;
  46.  
  47. #define NWORDS    1024
  48.  
  49. static char   **tmp_cmd;
  50. static int      tcs;
  51.  
  52. static Status x_get_window_attributes(Window w, XWindowAttributes *wa);
  53.  
  54. /* Search for an option in the tmp_cmd array. */
  55. static int
  56. cmd_srch(const char *s)
  57. {
  58.     int i;
  59.  
  60.     for (i = 1; i < tcs; i++)
  61.         if (tmp_cmd[i] && !strcmp(tmp_cmd[i], s))
  62.             return i;
  63.     return 0;
  64. }
  65.  
  66. /* Replace an options in the tmp_cmd array. */
  67. static void
  68. cmd_replace(int ix, const char *s)
  69. {
  70.     XtFree(tmp_cmd[ix]);
  71.     tmp_cmd[ix] = XtNewString(s);
  72. }
  73.  
  74. /* Append an option to the tmp_cmd array. */
  75. static void
  76. cmd_append(const char *s)
  77. {
  78.     tmp_cmd[tcs++] = XtNewString(s);
  79.     tmp_cmd[tcs] = (char *) NULL;
  80. }
  81.  
  82. /* Delete an option from the tmp_cmd array. */
  83. static void
  84. cmd_delete(int ix)
  85. {
  86.     XtFree(tmp_cmd[ix]);
  87.     tmp_cmd[ix] = (char *) NULL;
  88. }
  89.  
  90. /* Save the screen geometry. */
  91. static void
  92. save_xy(void)
  93. {
  94.     char tbuf[64];
  95.     Window window, frame, child;
  96.     XWindowAttributes wa;
  97.     int x, y;
  98.     int ix;
  99.  
  100.     window = XtWindow(toplevel);
  101.     if (!x_get_window_attributes(window, &wa))
  102.         return;
  103.     (void) XTranslateCoordinates(display, window, wa.root, 
  104.         -wa.border_width, -wa.border_width,
  105.         &x, &y, &child);
  106.  
  107.     frame = XtWindow(toplevel);
  108.     while (True) {
  109.         Window root, parent;
  110.         Window *wchildren;
  111.         unsigned int nchildren;
  112.  
  113.         int status = XQueryTree(display, frame, &root, &parent,
  114.             &wchildren, &nchildren);
  115.         if (status && wchildren)
  116.             XFree((char *)wchildren);
  117.         if (parent == root || !parent || !status)
  118.             break;
  119.         frame = parent;
  120.     }
  121.     if (frame != window) {
  122.         if (!x_get_window_attributes(frame, &wa))
  123.             return;
  124.         x = wa.x;
  125.         y = wa.y;
  126.     }
  127.  
  128.     (void) sprintf(tbuf, "+%d+%d", x, y);
  129.     if ((ix = cmd_srch("-geometry")))
  130.         cmd_replace(ix + 1, tbuf);
  131.     else {
  132.         cmd_append("-geometry");
  133.         cmd_append(tbuf);
  134.     }
  135. }
  136.  
  137. /* Save the icon information: state, label, geometry. */
  138. static void
  139. save_icon(void)
  140. {
  141.     unsigned char *data;
  142.     int iconX, iconY;
  143.     char tbuf[64];
  144.     int ix;
  145.     unsigned long nitems;
  146.  
  147.     {
  148.         Atom actual_type;
  149.         int actual_format;
  150.         unsigned long leftover;
  151.  
  152.         if (XGetWindowProperty(display, XtWindow(toplevel), a_state,
  153.             0L, 2L, False, a_state, &actual_type, &actual_format,
  154.             &nitems, &leftover, &data) != Success)
  155.             return;
  156.         if (actual_type != a_state ||
  157.             actual_format != 32 ||
  158.             nitems < 1)
  159.             return;
  160.     }
  161.  
  162.     ix = cmd_srch("-iconic");
  163.     if (*(unsigned long *)data == IconicState) {
  164.         if (!ix)
  165.             cmd_append("-iconic");
  166.     } else {
  167.         if (ix)
  168.             cmd_delete(ix);
  169.     }
  170.  
  171.     if (nitems < 2)
  172.         return;
  173.  
  174.     {
  175.         Window icon_window;
  176.         XWindowAttributes wa;
  177.         Window child;
  178.  
  179.         icon_window = *(Window *)(data + sizeof(unsigned long));
  180.         if (icon_window == None)
  181.             return;
  182.         if (!x_get_window_attributes(icon_window, &wa))
  183.             return;
  184.         (void) XTranslateCoordinates(display, icon_window, wa.root,
  185.             -wa.border_width, -wa.border_width, &iconX, &iconY,
  186.             &child);
  187.         if (!iconX && !iconY)
  188.             return;
  189.     }
  190.  
  191.     (void) sprintf(tbuf, "%d", iconX);
  192.     ix = cmd_srch(OptIconX);
  193.     if (ix)
  194.         cmd_replace(ix + 1, tbuf);
  195.     else {
  196.         cmd_append(OptIconX);
  197.         cmd_append(tbuf);
  198.     }
  199.  
  200.     (void) sprintf(tbuf, "%d", iconY);
  201.     ix = cmd_srch(OptIconY);
  202.     if (ix)
  203.         cmd_replace(ix + 1, tbuf);
  204.     else {
  205.         cmd_append(OptIconY);
  206.         cmd_append(tbuf);
  207.     }
  208.     return;
  209. }
  210.  
  211. /* Save the keymap information. */
  212. static void
  213. save_keymap(void)
  214. {
  215.        /* Note: keymap propogation is deliberately disabled, because it
  216.       may vary from workstation to workstation.  The recommended
  217.       way of specifying keymaps is through your .Xdefaults or the
  218.       KEYMAP or KEYBD environment variables, which can be easily set
  219.       in your .login or .profile to machine-specific values; the
  220.       -keymap switch is really for debugging or testing keymaps.
  221.  
  222.       I'm sure I'll regret this.  */
  223.  
  224. #if defined(notdef) /*[*/
  225.     if (appres.keymap) {
  226.         add_string(v, OptKeymap);
  227.         add_string(v, appres.keymap);
  228.     }
  229. #endif /*]*/
  230. }
  231.  
  232. /* Save the model name. */
  233. static void
  234. save_model(void)
  235. {
  236.     int ix;
  237.  
  238.     if (!model_changed)
  239.         return;
  240.     if ((ix = cmd_srch(OptModel)) && strcmp(tmp_cmd[ix], model_name))
  241.         cmd_replace(ix + 1, model_name);
  242.     else {
  243.         cmd_append(OptModel);
  244.         cmd_append(model_name);
  245.     }
  246. }
  247.  
  248. /* Save the emulator font. */
  249. static void
  250. save_efont(void)
  251. {
  252.     int ix;
  253.  
  254.     if (!efont_changed)
  255.         return;
  256.     if ((ix = cmd_srch(OptEmulatorFont)) && strcmp(tmp_cmd[ix], efontname))
  257.         cmd_replace(ix + 1, efontname);
  258.     else {
  259.         cmd_append(OptEmulatorFont);
  260.         cmd_append(efontname);
  261.     }
  262. }
  263.  
  264. #if defined(X3270_KEYPAD) /*[*/
  265. /* Save the keypad state. */
  266. static void
  267. save_keypad(void)
  268. {
  269.     int ix;
  270.  
  271.     ix = cmd_srch(OptKeypadOn);
  272.     if (appres.keypad_on || keypad_popped) {
  273.         if (!ix)
  274.             cmd_append(OptKeypadOn);
  275.     } else {
  276.         if (ix)
  277.             cmd_delete(ix);
  278.     }
  279. }
  280. #endif /*]*/
  281.  
  282. /* Save the scrollbar state. */
  283. static void
  284. save_scrollbar(void)
  285. {
  286.     int i_on, i_off;
  287.  
  288.     if (!scrollbar_changed)
  289.         return;
  290.     i_on = cmd_srch(OptScrollBar);
  291.     i_off = cmd_srch(OptNoScrollBar);
  292.     if (toggled(SCROLL_BAR)) {
  293.         if (!i_on) {
  294.             if (i_off)
  295.                 cmd_replace(i_off, OptScrollBar);
  296.             else
  297.                 cmd_append(OptScrollBar);
  298.         }
  299.     } else {
  300.         if (!i_off) {
  301.             if (i_on)
  302.                 cmd_replace(i_on, OptNoScrollBar);
  303.             else
  304.                 cmd_append(OptNoScrollBar);
  305.         }
  306.     }
  307. }
  308.  
  309. /* Save the name of the host we are connected to. */
  310. static void
  311. save_host(void)
  312. {
  313.     char *space;
  314.  
  315.     if (!CONNECTED)
  316.         return;
  317.     space = strchr(full_current_host, ' ');
  318.     if (space == (char *) NULL)
  319.         cmd_append(full_current_host);
  320.     else {
  321.         char *tmp = XtNewString(full_current_host);
  322.         char *port;
  323.  
  324.         space = strchr(tmp, ' ');
  325.         *space = '\0';
  326.         cmd_append(tmp);
  327.         port = space + 1;
  328.         while (*port == ' ')
  329.             port++;
  330.         if (*port)
  331.             cmd_append(port);
  332.         XtFree(tmp);
  333.     }
  334. }
  335.  
  336. /* Save the settings of each of the toggles. */
  337. static void
  338. save_toggles(void)
  339. {
  340.     int i, j;
  341.     int ix;
  342.  
  343.     for (i = 0; i < N_TOGGLES; i++) {
  344.         if (!appres.toggle[i].changed)
  345.             continue;
  346.  
  347.         /*
  348.          * Find the last "-set" or "-clear" for this toggle.
  349.          * If there is a preferred alias, delete them instead.
  350.          */
  351.         ix = 0;
  352.         for (j = 1; j < tcs; j++)
  353.             if (tmp_cmd[j] &&
  354.                 (!strcmp(tmp_cmd[j], OptSet) ||
  355.                  !strcmp(tmp_cmd[j], OptClear)) &&
  356.                 tmp_cmd[j+1] &&
  357.                 !strcmp(tmp_cmd[j+1], toggle_names[i].name)) {
  358.                 if (i == SCROLL_BAR
  359. #if defined(X3270_TRACE) /*[*/
  360.                     || i == DS_TRACE
  361. #endif /*]*/
  362.                     ) {
  363.                     cmd_delete(j);
  364.                     cmd_delete(j + 1);
  365.                 } else
  366.                     ix = j;
  367.         }
  368.  
  369.         /* Handle aliased switches. */
  370.         switch (i) {
  371.             case SCROLL_BAR:
  372.             continue;    /* +sb/-sb done separately */
  373. #if defined(X3270_TRACE) /*[*/
  374.             case DS_TRACE:
  375.             ix = cmd_srch(OptDsTrace);
  376.             if (appres.toggle[DS_TRACE].value) {
  377.                 if (!ix)
  378.                     cmd_append(OptDsTrace);
  379.             } else {
  380.                 if (ix)
  381.                     cmd_delete(ix);
  382.             }
  383.             continue;
  384. #endif /*]*/
  385.         }
  386.  
  387.         /* If need be, switch "-set" with "-clear", or append one. */
  388.         if (appres.toggle[i].value) {
  389.             if (ix && strcmp(tmp_cmd[ix], OptSet))
  390.                 cmd_replace(ix, OptSet);
  391.             else if (!ix) {
  392.                 cmd_append(OptSet);
  393.                 cmd_append(toggle_names[i].name);
  394.             }
  395.         } else {
  396.             if (ix && strcmp(tmp_cmd[ix], OptClear))
  397.                 cmd_replace(ix, OptClear);
  398.             else if (!ix) {
  399.                 cmd_append(OptClear);
  400.                 cmd_append(toggle_names[i].name);
  401.             }
  402.         }
  403.     }
  404. }
  405.  
  406. /* Remove a positional parameter from the command line. */
  407. static void
  408. remove_positional(char *s)
  409. {
  410.     char *c;
  411.  
  412.     c = cmd + cmd_len - 2;    /* last byte of last arg */
  413.     while (*c && c >= cmd)
  414.         c--;
  415.     if (strcmp(s, c + 1))
  416.         XtError("Command-line switches must precede positional arguments");
  417.     cmd_len = c - cmd;
  418. }
  419.  
  420. /* Save a copy of he XA_WM_COMMAND poperty. */
  421. void
  422. save_init(int argc, char *hostname, char *port)
  423. {
  424.     Atom actual_type;
  425.     int actual_format;
  426.     unsigned long nitems;
  427.     unsigned long bytes_after;
  428.  
  429.     /*
  430.      * Fetch the initial value of the XA_COMMAND property and store
  431.      * it in 'cmd'.
  432.      */
  433.     XGetWindowProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
  434.         0L, 1000000L, False, XA_STRING, &actual_type, &actual_format,
  435.         &nitems, &bytes_after, (unsigned char **)&cmd);
  436.     if (nitems == 0)
  437.         XtError("Could not get initial XA_COMMAND property");
  438.     cmd_len = nitems * (actual_format / 8);
  439.  
  440.     /*
  441.      * Now locate the hostname and port positional arguments, and
  442.      * remove them.  If they aren't the last two components of the
  443.      * command line, abort.
  444.      */
  445.     switch (argc) {
  446.         case 3:
  447.         remove_positional(port);
  448.         /* fall through */
  449.         case 2:
  450.         remove_positional(hostname);
  451.         break;
  452.     }
  453. }
  454.  
  455. /* Handle a WM_SAVE_YOURSELF ICCM. */
  456. void
  457. save_yourself(void)
  458. {
  459.     int i;
  460.     char *c, *c2;
  461.     int len;
  462.  
  463.     if (command_string != CN) {
  464.         XtFree(command_string);
  465.         command_string = CN;
  466.     }
  467.  
  468.     /* Copy the original command line into tmp_cmd. */
  469.     tmp_cmd = (char **) XtMalloc(sizeof(char *) * NWORDS);
  470.     tcs = 0;
  471.     i = 0;
  472.     c = cmd;
  473.     while (i < cmd_len) {
  474.         c = cmd + i;
  475.         tmp_cmd[tcs++] = XtNewString(c);
  476.         i += strlen(c);
  477.         i++;
  478.     }
  479.     tmp_cmd[tcs] = (char *) NULL;
  480.  
  481.     /* Replace the first element with the program name. */
  482.     cmd_replace(0, programname);
  483.  
  484.     /* Save options. */
  485.     save_xy();
  486.     save_icon();
  487.     save_keymap();
  488.     save_model();
  489.     save_efont();
  490. #if defined(X3270_KEYPAD) /*[*/
  491.     save_keypad();
  492. #endif /*]*/
  493.     save_scrollbar();
  494.     save_toggles();
  495.     save_host();
  496.  
  497.     /* Copy what's left into contiguous memory. */
  498.     len = 0;
  499.     for (i = 0; i < tcs; i++)
  500.         if (tmp_cmd[i])
  501.             len += strlen(tmp_cmd[i]) + 1;
  502.     c = XtMalloc(len);
  503.     c[0] = '\0';
  504.     c2 = c;
  505.     for (i = 0; i < tcs; i++)
  506.         if (tmp_cmd[i]) {
  507.             (void) strcpy(c2, tmp_cmd[i]);
  508.             c2 += strlen(c2) + 1;
  509.             XtFree(tmp_cmd[i]);
  510.         }
  511.     XtFree((XtPointer)tmp_cmd);
  512.  
  513.     /* Change the property. */
  514.     XChangeProperty(display, XtWindow(toplevel), XA_WM_COMMAND,
  515.         XA_STRING, 8, PropModeReplace, (unsigned char *)c, len);
  516.  
  517.     /* Save a readable copy of the command string for posterity. */
  518.     command_string = c;
  519.     while (((c2 = strchr(c, '\0')) != CN) &&
  520.            (c2 - command_string < len-1)) {
  521.         *c2 = ' ';
  522.         c = c2 + 1;
  523.     }
  524. }
  525.  
  526.  
  527. /* Support for x3270 profiles. */
  528.  
  529. #define PROFILE_ENV    "X3270PRO"
  530. #define NO_PROFILE_ENV    "NOX3270PRO"
  531. #define DEFAULT_PROFILE    "~/.x3270pro"
  532.  
  533. extern XrmOptionDescRec options[];
  534. extern int num_options;
  535.  
  536. char *profile_name = CN;
  537. static char *xcmd;
  538. static int xargc;
  539. static char **xargv;
  540.  
  541. #if defined(X3270_MENUS) /*[*/
  542.  
  543. /* Save one option in the file. */
  544. static void
  545. save_opt(FILE *f, const char *full_name, const char *opt_name,
  546.     const char *res_name, const char *value)
  547. {
  548.     (void) fprintf(f, "! %s (%s)\nx3270.%s: %s\n",
  549.         full_name, opt_name, res_name, value);
  550. }
  551.  
  552. /* Save the current options settings in a profile. */
  553. int
  554. save_options(char *n)
  555. {
  556.     FILE *f;
  557.     Boolean exists = False;
  558.     char *ct;
  559.     int i;
  560.     time_t clk;
  561.     char buf[64];
  562.     Boolean any_toggles = False;
  563.  
  564.     if (n == CN || *n == '\0')
  565.         return -1;
  566.  
  567.     /* Open the file. */
  568.     n = do_subst(n, True, True);
  569.     f = fopen(n, "r");
  570.     if (f != (FILE *)NULL) {
  571.         (void) fclose(f);
  572.         exists = True;
  573.     }
  574.     f = fopen(n, "a");
  575.     if (f == (FILE *)NULL) {
  576.         popup_an_errno(errno, "Cannot open %s", n);
  577.         XtFree(n);
  578.         return -1;
  579.     }
  580.  
  581.     /* Save the name. */
  582.     if (profile_name == CN)
  583.         XtFree(profile_name);
  584.     profile_name = n;
  585.  
  586.     /* Print the header. */
  587.     clk = time((time_t *)0);
  588.     ct = ctime(&clk);
  589.     if (ct[strlen(ct)-1] == '\n')
  590.         ct[strlen(ct)-1] = '\0';
  591.     if (exists)
  592.         (void) fprintf(f, "! File updated %s by %s\n", ct, build);
  593.     else
  594.         (void) fprintf(f,
  595. "! x3270 profile\n\
  596. ! File created %s by %s\n\
  597. ! This file overrides xrdb and .Xdefaults.\n\
  598. ! To skip reading this file, set %s in the environment.\n\
  599. !\n",
  600.             ct, build, NO_PROFILE_ENV);
  601.  
  602.     /* Save most of the toggles. */
  603.     for (i = 0; i < N_TOGGLES; i++) {
  604.         if (!appres.toggle[i].changed)
  605.             continue;
  606. #if defined(X3270_TRACE) /*[*/
  607.         if (i == DS_TRACE || i == SCREEN_TRACE || i == EVENT_TRACE)
  608.             continue;
  609. #endif /*]*/
  610.         if (!any_toggles) {
  611.             (void) fprintf(f, "! toggles (%s, %s)\n",
  612.                 OptSet, OptClear);
  613.             any_toggles = True;
  614.         }
  615.         (void) fprintf(f, "x3270.%s: %s\n", toggle_names[i].name,
  616.             appres.toggle[i].value ? ResTrue : ResFalse);
  617.     }
  618.  
  619. #if defined(X3270_KEYPAD) /*[*/
  620.     /* Save the keypad state. */
  621.     if (keypad_changed)
  622.         save_opt(f, "keypad state", OptKeypadOn, ResKeypadOn,
  623.             (appres.keypad_on || keypad_popped) ?
  624.                 ResTrue : ResFalse);
  625. #endif /*]*/
  626.  
  627.     /* Save other menu-changeable options. */
  628.     if (efont_changed)
  629.         save_opt(f, "emulator font", OptEmulatorFont, ResEmulatorFont,
  630.             efontname);
  631.     if (model_changed) {
  632.         (void) sprintf(buf, "%d", model_num);
  633.         save_opt(f, "model", OptModel, ResModel, buf);
  634.     }
  635.     if (oversize_changed) {
  636.         (void) sprintf(buf, "%dx%d", ov_cols, ov_rows);
  637.         save_opt(f, "oversize", OptOversize, ResOversize, buf);
  638.     }
  639.     if (scheme_changed && appres.color_scheme != CN)
  640.         save_opt(f, "color scheme", OptColorScheme, ResColorScheme,
  641.             appres.color_scheme);
  642.     if (keymap_changed && appres.key_map != (char *)NULL)
  643.         save_opt(f, "keymap", OptKeymap, ResKeymap, appres.key_map);
  644.     if (charset_changed && appres.charset != (char *)NULL)
  645.         save_opt(f, "charset", OptCharset, ResCharset, appres.charset);
  646.  
  647.     /* Done. */
  648.     (void) fclose(f);
  649.  
  650.     return 0;
  651. }
  652.  
  653. #endif /*]*/
  654.  
  655. /* Save a copy of the command-line options. */
  656. void
  657. save_args(int argc, char *argv[])
  658. {
  659.     int i;
  660.     int len = 0;
  661.  
  662.     for (i = 0; i < argc; i++)
  663.         len += strlen(argv[i]) + 1;
  664.     xcmd = XtMalloc(len + 1);
  665.     xargv = (char **)XtMalloc((argc + 1) * sizeof(char *));
  666.     len = 0;
  667.     for (i = 0; i < argc; i++) {
  668.         xargv[i] = xcmd + len;
  669.         (void) strcpy(xcmd + len, argv[i]);
  670.         len += strlen(argv[i]) + 1;
  671.     }
  672.     xargv[i] = CN;
  673.     *(xcmd + len) = '\0';
  674.     xargc = argc;
  675. }
  676.  
  677. /* Merge in the options settings from a profile. */
  678. void
  679. merge_profile(XrmDatabase *d)
  680. {
  681.     const char *fname;
  682.     XrmDatabase dd;
  683.  
  684.     /* Open the file. */
  685.     if (getenv(NO_PROFILE_ENV) != CN) {
  686.         profile_name = do_subst(DEFAULT_PROFILE, True, True);
  687.         return;
  688.     }
  689.     fname = getenv(PROFILE_ENV);
  690.     if (fname == CN || *fname == '\0')
  691.         fname = DEFAULT_PROFILE;
  692.     profile_name = do_subst(fname, True, True);
  693.  
  694.     /* Create a resource database from the file. */
  695.     dd = XrmGetFileDatabase(profile_name);
  696.     if (dd == NULL)
  697.         goto done;
  698.  
  699.     /* Merge in the profile options. */
  700.     XrmMergeDatabases(dd, d);
  701.  
  702.     /* Merge the saved command-line options back on top of those. */
  703.     dd = NULL;
  704.     XrmParseCommand(&dd, options, num_options, programname, &xargc, xargv);
  705.     XrmMergeDatabases(dd, d);
  706.  
  707.     done:
  708.     /* Free the saved command-line options. */
  709.     XtFree(xcmd);
  710.     xcmd = CN;
  711.     XtFree((char *)xargv);
  712.     xargv = (char **)NULL;
  713. }
  714.  
  715. /*
  716.  * Safe routine for querying window attributes
  717.  */
  718. static int
  719. dummy_error_handler(Display *d unused, XErrorEvent *e unused)
  720. {
  721.     return 0;
  722. }
  723.  
  724. static Status
  725. x_get_window_attributes(Window w, XWindowAttributes *wa)
  726. {
  727.     XErrorHandler old_handler;
  728.     Status s;
  729.  
  730.     old_handler = XSetErrorHandler(dummy_error_handler);
  731.  
  732.     s = XGetWindowAttributes(display, w, wa);
  733.     if (!s)
  734.         (void) fprintf(stderr, "Error: querying bad window 0x%lx\n", w);
  735.  
  736.     (void) XSetErrorHandler(old_handler);
  737.  
  738.     return s;
  739. }
  740.